home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Mania 5
/
MacMania 5.toast
/
/
Internet software
/
NewsWatcher
/
NW Source
/
Source
/
datetime.c
< prev
next >
Wrap
Text File
|
1997-01-09
|
7KB
|
346 lines
/*----------------------------------------------------------------------------
datetime.c
This module converts RFC822 date/time lines into Mac-format date/time
strings in local time.
Copyright © 1994-1997, Northwestern University.
----------------------------------------------------------------------------*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include "glob.h"
#include "datetime.h"
#include "strutil.h"
/*----------------------------------------------------------------------------
Skip
Skip white space and comments.
Entry: *str = string.
Exit: *str = pointer to first character following skipped white space
and comments.
----------------------------------------------------------------------------*/
static void Skip (char **str)
{
char *s;
short parenLevel;
s = *str;
while (true) {
while (isLWSP(*s)) s++;
if (*s == '(') {
parenLevel = 1;
s++;
while (*s != 0 && parenLevel > 0) {
if (*s == '(') {
parenLevel++;
} else if (*s == ')') {
parenLevel--;
}
s++;
}
} else {
break;
}
}
*str = s;
}
/*----------------------------------------------------------------------------
ParseNum
Extract a long integer from a string.
Entry: *str = string.
min = minimum number of digits.
max = maximum number of digits.
Exit: function result = true if number parsed, false if syntax error.
*num = the number
*str = pointer to first character following parsed number.
----------------------------------------------------------------------------*/
static Boolean ParseNum (char **str, short min, short max, short *num)
{
short n, numDigits;
char *p;
p = *str;
if (!isdigit(*p)) return false;
n = CrackNum(&p);
numDigits = p - *str;
if (numDigits < min || numDigits > max) return false;
*str = p;
*num = n;
return true;
}
/*----------------------------------------------------------------------------
FindDayOfWeek
Given a string that might be a day of week abbreviation, return the number
of the day of the week (starting with Monday = 1, ...).
Entry: str = day of week string.
Exit: function result = day of week ordinal, or 0 if can't parse.
----------------------------------------------------------------------------*/
static short FindDayOfWeek (char *str)
{
static char *days[7] = {
"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"
};
short i;
for (i = 0; i < 7; i++) {
if (MyStrNEqual(str, days[i], 3)) return i+1;
}
return 0;
}
/*----------------------------------------------------------------------------
FindMonth
Given a string that might be a month abbreviation, return the number
of the month (starting with January = 1, ...).
Entry: str = month string.
Exit: function result = month ordinal, or 0 if can't parse.
----------------------------------------------------------------------------*/
static short FindMonth (char *str)
{
static char *months[12] = {
"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
"JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
};
short i;
for (i = 0; i < 12; i++) {
if (MyStrNEqual(str, months[i], 3)) return i+1;
}
return 0;
}
/*----------------------------------------------------------------------------
Parse822Date
Parse a date/time that's in RFC822/1123 header format:
Entry: date = RFC822/1123 date/time string.
Exit: function result = number of seconds since January 1, 1904,
the standard Mac date convention.
function result = 0 if the date could not be parsed.
date-time = [ day "," ] date time
day = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
date = 1*2DIGIT month 2*4DIGIT
month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
"Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
time = hour zone
hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT]
zone = "UT" / "GMT" / "EST" / "EDT" / "CST" / "CDT" /
"MST" / "MDT" / "PST" / "PDT" / ( ("+" / "-") 4DIGIT
----------------------------------------------------------------------------*/
unsigned long Parse822Date (char *date)
{
DateTimeRec dt;
unsigned long result;
char *p;
short sign = 1;
short tzDelta = 0;
memset(&dt, 0, sizeof(dt));
p = date;
/* Day of week and comma. */
Skip(&p);
if (isalpha(*p)) {
if (FindDayOfWeek(p) == 0) return 0;
p+= 3;
Skip(&p);
if (*p != ',') return 0;
p++;
}
/* Date. */
Skip(&p);
if (!ParseNum(&p, 1, 2, &dt.day)) return 0;
Skip(&p);
dt.month = FindMonth(p);
if (dt.month == 0) return 0;
p += 3;
Skip(&p);
if (!ParseNum(&p, 2, 4, &dt.year)) return 0;
if (dt.year < 21) {
dt.year += 2000;
} else if (dt.year < 100) {
dt.year += 1900;
}
/* Time. */
Skip(&p);
if (!ParseNum(&p, 1, 2, &dt.hour)) return 0;
Skip(&p);
if (*p != ':') return 0;
p++;
Skip(&p);
if (!ParseNum(&p, 2, 2, &dt.minute)) return 0;
Skip(&p);
if (*p == ':') {
p++;
Skip(&p);
if (!ParseNum(&p, 2, 2, &dt.second)) return 0;
}
/* Zone. */
Skip(&p);
if (isalpha(*p)) {
if (MyStrNEqual(p, "GMT", 3)) {
tzDelta = 0;
p += 3;
} else if (MyStrNEqual(p, "UT", 2)) {
tzDelta = 0;
p += 2;
} else if (MyStrNEqual(p, "EST", 3)) {
sign = -1;
tzDelta = 500;
p += 3;
} else if (MyStrNEqual(p, "EDT", 3)) {
sign = -1;
tzDelta = 400;
p += 3;
} else if (MyStrNEqual(p, "CST", 3)) {
sign = -1;
tzDelta = 600;
p += 3;
} else if (MyStrNEqual(p, "CDT", 3)) {
sign = -1;
tzDelta = 500;
p += 3;
} else if (MyStrNEqual(p, "MST", 3)) {
sign = -1;
tzDelta = 700;
p += 3;
} else if (MyStrNEqual(p, "MDT", 3)) {
sign = -1;
tzDelta = 600;
p += 3;
} else if (MyStrNEqual(p, "PST", 3)) {
sign = -1;
tzDelta = 800;
p += 3;
} else if (MyStrNEqual(p, "PDT", 3)) {
sign = -1;
tzDelta = 700;
p += 3;
} else {
return 0;
}
} else if (*p == '+' || *p == '-') {
sign = *p == '+' ? +1 : -1;
p++;
Skip(&p);
if (!ParseNum(&p, 4, 4, &tzDelta)) return 0;
} else {
return 0;
}
Skip(&p);
if (*p != 0) return 0;
/* Convert to seconds since 1/1/1904 */
DateToSeconds(&dt, &result);
result -= sign * (3600*((long)tzDelta/100) + 60*((long)tzDelta%100));
return result;
}
/*----------------------------------------------------------------------------
Cleanup822Date
Converts an RFC822 date/time string into a Mac-style date/time string
in local time.
Entry: date = RFC822 date/time string.
Exit: date = Mac-style date/time string.
If the string cannot be parsed or converted, or if the the use has
not set the local time zone, the string is unchanged.
----------------------------------------------------------------------------*/
void Cleanup822Date (char *date)
{
MachineLocation loc;
long gmtOffset;
unsigned long secs;
Str255 time;
/* Get our location. Return if Map control panel not installed. */
ReadLocation(&loc);
if (loc.latitude == 0 && loc.longitude == 0 && loc.u.gmtDelta == 0) return;
/* Get our offset in seconds from GMT. */
gmtOffset = loc.u.gmtDelta & 0x00FFFFFF;
if ((gmtOffset & 0x00800000) != 0) gmtOffset |= 0xFF000000;
/* Try to parse the date we were passed. */
secs = Parse822Date(date);
if (secs == 0) return;
/* Correct for our timezone. */
secs += gmtOffset;
/* Convert it back into a Mac-style date/time string. */
IUDateString(secs, abbrevDate, (StringPtr)date);
p2cstr((StringPtr)date);
strcat(date, " ");
IUTimeString(secs, true, time);
strcat(date, p2cstr(time));
}